/**
 * @file       LCDApp.cpp
 * @brief      TODO
 * @author     Huabo Zheng
 * @date       Jan 12, 2012
 * @Copyright  2012, www.netgear.com Inc. All rights reserved.
 */

#include "LCDApp.h"
#include "typedefine.h"
#include "errorcode.h"
#include "Panel.h"
#include "IEvent.h"
#include "Context.h"
#include "EventQueue.h"
#include "Frame.h"
#include "KeyboardThread.h"
#include "lcd/LCDFactory.h"
#include <cstdlib>
#include <stdlib.h>
#include <sys/stat.h>
#include <pthread.h>
#include <string.h>
#include <signal.h>
#include <unistd.h>


namespace NS_LCD_AFW
{

static volatile bool g_bRunning = true;

CLCDApp::CLCDApp()
{
	m_pCurApp = this;
	m_strAppName = "";

}

CLCDApp::~CLCDApp()
{
}

int CLCDApp::setDaemonize()
{
	pid_t pid;
	if ((pid = fork()) < 0)
	{
		return -1;
	}
	else if (pid != 0)
	{
		// parent exit
		exit(0);
	}

	setsid();
	//chdir("/");
	umask(0);

	close(0);
	close(1);
	close(2);
	return ERR_SUCCESS;
}

void CLCDApp::signalFunc(int signo)
{
	g_bRunning = false;
}

int CLCDApp::hookSignal(int signo, void(*func)(int))
{
	struct sigaction act, oact;
	memset(&act, 0x00, sizeof(struct sigaction));
	sigemptyset(&act.sa_mask);
	//act.sa_sigaction = func;
	act.sa_handler = func;
	act.sa_flags = SA_RESTART;
	int iRet = sigaction(signo, &act, &oact);
	return iRet;
}

CLCDApp *CLCDApp::GetApp() const
{
	return m_pCurApp;
}

int CLCDApp::initInstance()
{
	if (ERR_SUCCESS != AfwGetLCDFactory()->createDisplayDevice(0)->initialize())
	{
		return ERR_INIT_LCD_FAILED;
	}

	if (ERR_SUCCESS != AfwGetKeyboardThread()->start())
	{
		return ERR_START_KEYBOAD_THREAD_FAILED;
	}

	return this->onInitInstance();
}

int CLCDApp::onInitInstance()
{
	return ERR_SUCCESS;
}

int CLCDApp::onExitInstance()
{
	return ERR_SUCCESS;
}

int CLCDApp::run()
{
	hookSignal(SIGINT, signalFunc);
	hookSignal(SIGTERM, signalFunc);

	IEvent *pEvent = NULL;
	long lCount = 0;
	try
	{
		while (g_bRunning)
		{
			if (ERR_SUCCESS == this->peekEvent(pEvent))
			{
				if (!this->pumpEvent(pEvent))
				{
					OBJ_DESTORY(pEvent);
					return this->exitInstance();
				}

				this->preTranslateEvent(pEvent);
				this->translateEvent(pEvent);
				this->dispatchEvent(pEvent);
				//			if (isIdleEvent(pEvent))
				//			{
				//				this->onIdle();
				//			}
				lCount = 0;
			}
			else
			{
				this->onIdle(++lCount);
				//TODO: don't sleep,I will add notification mechanism for the msg queue soon
				usleep(100);
			}
			OBJ_DESTORY(pEvent);
		}
		OBJ_DESTORY(pEvent);
		return this->exitInstance();
	}
	catch (...)
	{
		OBJ_DESTORY(pEvent);
		this->exitInstance();
		return ERR_UNKNOW_EXECPTION_HAPPEN;
	}
}

int CLCDApp::initApp(int argc, char *argv[])
{
	return ERR_SUCCESS;
}

int CLCDApp::exitInstance()
{
	AfwGetKeyboardThread()->stop();

	int iRet = this->onExitInstance();

	AfwGetLCDFactory()->createDisplayDevice(0)->unInitialize();

	return iRet;
}

int CLCDApp::peekEvent(IEvent *&pEvent)
{
	if (AfwGetAppEventQueue()->peekEvent(pEvent)
			|| AfwGetSysEventQueue()->peekEvent(pEvent))
	{
		return ERR_SUCCESS;
	}

	return ERR_EVENT_QUEUE_EMPTY;
}

int CLCDApp::onIdle(long lCount)
{
	return ERR_SUCCESS;
}

int CLCDApp::onBusy(long lCount)
{
	return ERR_SUCCESS;
}

bool CLCDApp::pumpEvent(IEvent *&pEvent)
{
	if (!AfwGetAppEventQueue()->getEvent(pEvent)
			&& !AfwGetSysEventQueue()->getEvent(pEvent))
	{
		return false;
	}

	if (IEvent::APP_EXIT_EVENT_CODE == pEvent->getCode())
	{
		return false;
	}
	return true;
}

bool CLCDApp::translateEvent(IEvent * pEvent)
{

	return true;
}

bool CLCDApp::preTranslateEvent(IEvent *pEvent)
{
	return true;
}

bool CLCDApp::dispatchEvent(IEvent *pEvent)
{
	if (NULL == pEvent)
	{
		return false;
	}

	CPanel *pActiveHandler = AfwGetContext()->getActivePanel();
	if (NULL == pActiveHandler)
	{
		return false;
	}

	int iRet = pActiveHandler->handler(pEvent);
	if (IEvent::APP_EVENT_CODE == pEvent->getCode()
			&& PANEL_CLOSE_EVENT_ID == pEvent->getEventId())
	{
		if (ERR_SUCCESS == iRet && pActiveHandler != this->GetMainPanel())
		{
			OBJ_DESTORY(pActiveHandler);
			if (NULL != AfwGetContext()->getActivePanel())
			{
				//AfwGetContext()->getActivePanel()->show();
			}
			else
			{
				GetMainPanel()->show();
			}
		}
	}
	else if (ERR_NO_FOCUS_OBJECT == iRet)
	{
		return false;
	}

	return true;
}

}

/* namespace NS_LCD_AFW */
